jetcrab\bytecode\statements/
switch_statement.rs1use crate::ast::Node;
2use crate::vm::instructions::Instruction;
3use crate::vm::types::CodeAddress;
4
5use super::ControlFlowCore;
6
7pub fn generate_switch_statement<T>(this: &mut T, node: &Node)
8where
9 T: ControlFlowCore,
10{
11 if let Node::SwitchStatement(stmt) = node {
12 this.visit_node(&stmt.discriminant);
14
15 this.instructions().push(Instruction::Dup);
17
18 let mut case_jumps = Vec::new();
20 let mut case_bodies = Vec::new();
21 let mut case_tests = Vec::new();
22
23 for case in &stmt.cases {
24 if let Some(test) = &case.test {
25 this.visit_node(test);
27
28 this.instructions().push(Instruction::Eq);
30
31 let jump_pos = this.instructions().len();
33 this.instructions()
34 .push(Instruction::JumpIfTrue(CodeAddress::new(0))); case_jumps.push(jump_pos);
36 case_tests.push(true);
37 } else {
38 case_jumps.push(0);
40 case_tests.push(false);
41 }
42
43 let body_start = this.instructions().len();
45 case_bodies.push(body_start);
46
47 for cons in &case.consequent {
49 this.visit_node(cons);
50 }
51
52 let _jump_to_end_pos = this.instructions().len();
54 this.instructions()
55 .push(Instruction::Jump(CodeAddress::new(0))); if let Some(jump_pos) = case_jumps.last_mut() {
59 if *jump_pos > 0 {
60 this.instructions()[*jump_pos] =
61 Instruction::JumpIfTrue(CodeAddress::new(body_start));
62 }
63 }
64 }
65
66 let switch_end = this.instructions().len();
68
69 for i in case_bodies {
71 if i < this.instructions().len() - 1 {
73 if let Instruction::Jump(addr) = &this.instructions()[i + 1] {
74 if addr.as_usize() == 0 {
75 this.instructions()[i + 1] =
76 Instruction::Jump(CodeAddress::new(switch_end));
77 }
78 }
79 }
80 }
81
82 this.instructions().push(Instruction::Pop);
84 }
85}